package com.tqjc.execute.work;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.tqjc.area.entity.Roller;
import com.tqjc.area.entity.SteelPlate;
import com.tqjc.area.entity.Stock;
import com.tqjc.area.service.CarSemiAutoService;
import com.tqjc.area.service.RollerService;
import com.tqjc.area.service.SteelPlateService;
import com.tqjc.area.service.impl.StockServiceImpl;
import com.tqjc.common.ScheduledTask.AccessControlScheduleTask;
import com.tqjc.execute.cache.TaskStatus;
import com.tqjc.execute.cache.entity.WorkStatus;
import com.tqjc.execute.consts.WorkConst;
import com.tqjc.execute.crane.entity.CraneInfo;
import com.tqjc.execute.crane.service.CraneInfoService;
import com.tqjc.execute.exception.TaskRunningException;
import com.tqjc.execute.exception.UpstreamSteelInfoException;
import com.tqjc.execute.task.entity.OcrResult;
import com.tqjc.execute.task.entity.Task;
import com.tqjc.execute.task.entity.TaskApart;
import com.tqjc.execute.task.service.TaskService;
import com.tqjc.execute.task.service.TaskStepService;
import com.tqjc.execute.thread.aysn.AysnAlignThread;
import com.tqjc.execute.thread.aysn.AysnEasyPlaceThread;
import com.tqjc.execute.utils.*;
import com.tqjc.mes.entity.SteelInfo;
import com.tqjc.mes.service.SteelInfoService;
import com.tqjc.mes.service.TestService;
import com.tqjc.system.common.constant.GlobalConstant;
import com.tqjc.system.core.redis.TaskRedisApi;
import com.tqjc.system.core.threadpool.ThreadPoolManager;
import com.tqjc.system.core.util.ShiroUtils;
import com.tqjc.system.core.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

@Slf4j
public abstract class AbsCraneWork implements CraneWork {

    @Resource
    PlcOperator plcOperator;

    @Resource
    CraneInfoService craneInfoService;

    @Resource
    RollerService rollerService;

    @Resource
    StockServiceImpl stockService;

    @Resource
    TaskStepService taskStepService;

    @Resource
    TaskService taskService;

    @Resource
    TaskRedisApi taskRedisApi;

    @Resource
    SteelPlateService steelPlateService;

    @Resource
    TestService testService;

    @Resource
    AccessControlScheduleTask accessControlScheduleTask;

    @Resource
    TaskStatus taskStatus;

    @Resource
    SteelInfoService steelInfoService;

    @Value("${server_host}")
    private String serverHost;

    @Autowired
    private RestTemplate restTemplate;


    //定义线程锁，保证线程安全
    Object lock = new Object();

    //定义任务启动标志位
    private volatile Boolean startLogo = false;

    private volatile Boolean semiAutoRunFlag = false;

    private volatile int semiAutoNowStep = 0;  //共4步

    private volatile int craneStatus = 0; //0为正常，非0为故障

    public volatile String stockNo="1";   //DJ2DJ3  选择的垛位号

    public volatile int stockPlaceNumber=1;   //堆垛张数

    public volatile Boolean isSteelNoChecked=false;  //2号横移钢板号确认

    public volatile String steelNoUpdated="";  //2号横移更正后的钢板号

    public volatile Boolean isSteelInfoChecked=false;  //天车钢板info输入与确认

    public volatile SteelPlate steelInfoWrite=new SteelPlate();   //天车钢板info输入与确认

    //当前工作的线程
    private volatile Runnable workThread;

    //当前任务累积吸取的张数
    private int suckedNum;

    @Override
    public abstract String getCraneType();

    @Autowired
    private CarSemiAutoService carSemiAutoService;

    @Override
    public synchronized void setStockNo(String stockNo) {
          this.stockNo=stockNo;
    }
    @Override
    public synchronized String getStockNo(){
        return this.stockNo;
    }
    @Override
    public synchronized void setStockPlaceNumber(int stockPlaceNumber){
        this.stockPlaceNumber=stockPlaceNumber;
        String craneType = this.getCraneType();
        WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(craneType);
        workStatus.setStockNumber(stockPlaceNumber);
        workStatus.setStockNumberFlag(true);
        taskStatus.setWorkStatusByCraneType(craneType,workStatus);
    }

    @Override
    public synchronized int getStockPlaceNumber(){
        return stockPlaceNumber;
    }

    @Override
    public synchronized void setIsSteelNoChecked(Boolean isSteelNoChecked){
        this.isSteelNoChecked=isSteelNoChecked;
    }
    @Override
    public synchronized Boolean getIsSteelNoChecked(){
        return this.isSteelNoChecked;
    }

    @Override
    public synchronized void setSteelNoUpdated(String  steelNoUpdated){
        this.steelNoUpdated=steelNoUpdated;
    }

    @Override
    public synchronized String  getSteelNoUpdated(){
        return this.steelNoUpdated;
    }

    @Override
    public synchronized void setIsSteelInfoChecked(Boolean isSteelInfoChecked){
        this.isSteelInfoChecked=isSteelInfoChecked;
    }
    @Override
    public synchronized Boolean getIsSteelInfoChecked(){
        return this.isSteelInfoChecked;
    }
    @Override
    public synchronized void setSteelInfoWrite(SteelPlate steelInfoWrite){
        this.steelInfoWrite=steelInfoWrite;
    }
    @Override
    public synchronized SteelPlate getSteelInfoWrite(){
        return this.steelInfoWrite;
    }



    //存储现在正在运行的线程
    public Runnable nowThread = null;


    @Override
    public synchronized void setStartLogo(Boolean startLogo) {
        this.startLogo = startLogo;
    }

    @Override
    public synchronized void setCraneStatus(int craneStatus) {
        this.craneStatus = craneStatus;
    }

    @Override
    public synchronized boolean getStartLogo() {
        return this.startLogo;
    }

    @Override
    public synchronized int getCraneStatus() {
        return this.craneStatus;
    }

    @Override
    public synchronized void setSemiAutoRunFlag(Boolean semiAutoRunFlag) {
        this.semiAutoRunFlag = semiAutoRunFlag;
    }

    @Override
    public synchronized void setSemiAutoNowStep(int semiAutoNowStep) {
        this.semiAutoNowStep = semiAutoNowStep;
    }

    @Override
    public synchronized int getSemiAutoNowStep() {
        return this.semiAutoNowStep;
    }

    @Override
    public synchronized boolean getSemiAutoRunFlag() {
        return this.semiAutoRunFlag;
    }

    @Override
    public void stopWork() {
        try {
            setStartLogo(false);
//            if (nowThread != null) {
//                ThreadPoolOperator.getInstance().interruptWorkThread(nowThread);
//            }

        } catch (Exception e) {
            log.error("停止任务线程出现异常",e);
        }
    }


    @Override
    public PublicResult startWork() {   //吸一块钢板的启动自动任务

        PublicResult result = checkPostWorkCondition();
        if (result.isSuccess()) {
            this.startLogo = true;
            taskStatus.setUnnormalByCraneType(getCraneType(),"");
            Runnable craneWorkRunnable = () -> {
                try {
                    //当标志位为true时，持续执行任务
                    while (startLogo) {
                        try {
                            if(!isRemoteAutoMode()){
                                startLogo=false;
                                taskStatus.setUnnormalByCraneType(getCraneType(),"天车被切换到非远程自动模式，被迫停止自动");
                                log.info("天车：{}被切换到非远程自动模式，被迫停止自动",getCraneType());
                                break;
                            }
                            //生成任务
                            Task task = getCraneTask(1);

                            if (task != null) {
                                task.setTaskType("auto");
                                //设置任务开始时间
                                task.setBeginTime(new Date());
                                task.setTaskStatus(0);
                                task = taskService.insert(task);
                                //TODO 需要改
                                log.info("自动任务生成成功，天车编号{},任务类型{}",getCraneType(), task.getType());
                                //此两个redis缓存，为了当自动任务中断，要半自动收场，提供任务信息
                                taskRedisApi.set(getCraneType()+"_taskId",task.getId());
                                //根据任务获取当前任务的所有步骤
                                PublicResult<List<TaskApart>> stepResult = getStepsByTask(task);
                                //如果生成成功,分配任务准备执行
                                if (stepResult.isSuccess()) {
                                    //log.info("任务步骤生成成功，天车编号{},任务类型{}", getCraneType(), task.getType());

                                    //修改工作状态
                                    WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                                    workStatus.setNowTask("自动");
                                    workStatus.setNowMode(task.getType());
                                    workStatus.setUnnormalStatus("");
                                    taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);

                                    List<TaskApart> taskApartList = stepResult.getData();
                                    for (TaskApart taskApart : taskApartList) {
                                        taskApart.setTaskApartByTask(task);
                                        if("place".equals(taskApart.getType())||"place-roller".equals(taskApart.getType())){
                                            boolean isSucked=plcOperator.checkIsSuckedSteel(getCraneType());
                                            while (!isSucked){
                                                if(!startLogo){
                                                    break;
                                                }
                                                isSucked=plcOperator.checkIsSuckedSteel(getCraneType());
                                                taskStatus.setUnnormalByCraneType(getCraneType(),"检测到吊具未吸板，任务暂停");
                                                Thread.sleep(20);
                                            }
                                            if(isSucked){
                                                taskStatus.setUnnormalByCraneType(getCraneType(),"");
                                                taskApart.action();
                                            }else{
                                                taskStatus.setUnnormalByCraneType(getCraneType(),"吸板步骤异常，未吸板放弃放板步骤");
                                                log.info("天车{}自动任务吸板步骤异常，未吸板放弃放板步骤",getCraneType());
                                            }
                                            /*//2号横移钢板号确认恢复初始值
                                            this.isSteelNoChecked=false;
                                            this.steelNoUpdated="";*/
                                        }else {  //吸板步骤的情况
                                            boolean isSucked=plcOperator.checkIsSuckedSteel(getCraneType());
                                            if(!isSucked){
                                                taskApart.action();
                                            }else{
                                                log.info("天车{}自动任务吸板步骤检测到吊具有板，放弃吸板步骤",getCraneType());
                                            }
                                        }

                                    }
                                }
                                task.setEndTime(new Date());
                                taskService.saveOrUpdate(task);
                                taskStatus.setTaskStatusByCraneType(getCraneType(), "");
                                this.suckedNum++;
                                WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                                workStatus.setSuckedNum("" + suckedNum);
                                workStatus.setNowStatus("运行中");
                                workStatus.setNowMode("");
                                taskStatus.setWorkStatusByCraneType(getCraneType(),workStatus);
                                taskStatus.setWorkModeByCraneType(getCraneType(), "");
                                log.info("天车{}自动任务当前吸板板数为：{}",getCraneType(),suckedNum);
                            }
                            Thread.sleep(100);
                        } catch (UpstreamSteelInfoException steelInfoException){
                            this.startLogo = false;
                            taskStatus.setUnnormalByCraneType(getCraneType(),steelInfoException.getMessage());
                        } catch (TaskRunningException ee){
                            log.info("天车{}自动任务接受到任务停止信号，线程停止",getCraneType());
                            this.startLogo = false;
                            taskStatus.setUnnormalByCraneType(getCraneType(),"自动任务接受到任务停止信号,任务已被停止");
                        } catch (Exception e) {
                            taskStatus.setUnnormalByCraneType(getCraneType(),e.getMessage());
                            /*//2号横移钢板号确认恢复初始值
                            this.isSteelNoChecked=false;
                            this.steelNoUpdated="";*/
                            log.error(e.getMessage(),e);
                            e.printStackTrace();
                        }
                        taskRedisApi.del(getCraneType()+"_taskId");
                    }
                    log.info("=====天车:{}自动任务完成=========",getCraneType());


                } catch (Exception e) {
                    log.error("天车:{}自动任务线程运行出现异常",getCraneType(),e);
                    e.printStackTrace();

                }
            };

            setNowThread(craneWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneWorkRunnable);
            return PublicResult.ok("启动成功");


        }
        return PublicResult.fail(result.getMsg());
    }

    @Override
    public PublicResult move1() {
        PublicResult result = checkNowStepAndIsHelp(1);
        if (result.isSuccess()) {
            this.semiAutoRunFlag = true;
            this.semiAutoNowStep=1;
            Runnable craneSemiAutoWorkRunnable = () -> {
                boolean resetStepFlag=true;   //恢复semiAutoRunFlag，semiAutoNowStep值
                try {
                    //调试suck多块板用：steelsCount  start
                    int steelsCount=1;
                    //调试suck多块板用：steelsCount  end
                    //生成任务
                    Task task = getCraneTask(steelsCount);
                    if (task != null) {
                        resetStepFlag=false;
                        log.info("用户{}启动了半自动步骤1，任务生成成功，天车编号{},任务类型{}", ShiroUtils.getSessionUserName(), getCraneType(), task.getType()); //type：offline，online
                        task.setTaskType("semiauto");
                        //设置任务开始时间
                        task.setBeginTime(new Date());
                        task = taskService.insert(task);
                        taskRedisApi.set(getCraneType()+"_taskId",task.getId());
                        if("offline".equalsIgnoreCase(task.getType())){
                            String str= JSON.toJSONString(task.getSteel4OfflineCur());
                            taskRedisApi.set(getCraneType()+"_steelInfo",str);
                        }
                        //根据任务获取当前任务的所有步骤
                        PublicResult<TaskApart> stepResult = getSemiAutoNowStepBean(1);
                        //如果生成成功,分配任务准备执行
                        if (stepResult.isSuccess()) {
                            //修改工作状态
                            WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                            workStatus.setNowTask("半自动");
                            workStatus.setNowMode(task.getType());
                            taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);

                            TaskApart taskApart = stepResult.getData();
                            taskApart.setTaskApartByTask(task);
                            taskApart.action();
                        }
                        taskStatus.setTaskStatusByCraneType(getCraneType(), "");
                        taskStatus.setWorkModeByCraneType(getCraneType(), "");

                    } else {
                        WorkStatus status = taskStatus.getWorkStatusByCraneType(getCraneType());
                        status.setUnnormalStatus("当前步骤生成任务失败");
                        taskStatus.setWorkStatusByCraneType(getCraneType(), status);
                    }
                } catch (Exception e) {
                    resetStepFlag=true;
                    log.error(e.getMessage(),e);
                    e.printStackTrace();
                }
                finally {
                    if(!resetStepFlag){
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=2;
                    }else {
                        log.debug("move1 resetStepFlag生效");
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=0;
                    }
                }
            };

            setNowThread(craneSemiAutoWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneSemiAutoWorkRunnable);
            return PublicResult.ok("启动成功");
        }
        return PublicResult.fail(result.getMsg());
    }

    @Override
    public PublicResult suck2() {

        PublicResult result = checkNowStepAndIsHelp(2);
        if (result.isSuccess()) {
            this.semiAutoRunFlag = true;
            Runnable craneSemiAutoWorkRunnable = () -> {
                boolean resetStepFlag=true;
                try {

                    if(!taskRedisApi.hasKey(getCraneType()+"_taskId")){
                        log.info("{}天车，用户{}执行半自动步骤2，缓存中无任务id，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                        this.semiAutoRunFlag =false;
                        this.semiAutoNowStep=0;
                        return;
                    }
                    Integer taskId=(Integer) taskRedisApi.get(getCraneType()+"_taskId");
                    Task task= taskService.queryById(taskId);
                    if(task==null){
                        log.info("{}天车，用户{}执行半自动步骤2，数据库中无当前任务，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                        this.semiAutoRunFlag =false;
                        this.semiAutoNowStep=0;
                        return;
                    }
                    if("offline".equalsIgnoreCase(task.getType())){
                        if(!taskRedisApi.hasKey(getCraneType()+"_steelInfo")){
                            log.info("{}天车，用户{}执行半自动步骤2，缓存中无钢板信息，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                            this.semiAutoRunFlag =false;
                            this.semiAutoNowStep=0;
                            return;
                        }
                        String steelPlateStr= (String)taskRedisApi.get(getCraneType()+"_steelInfo");
                        SteelPlate steelPlate= JSON.parseObject(steelPlateStr,SteelPlate.class);
                        if(steelPlate==null){
                            log.info("{}天车，用户{}执行半自动步骤2，从缓存中获取的钢板信息为空，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                            this.semiAutoRunFlag =false;
                            this.semiAutoNowStep=0;
                            return;
                        }
                        task.setSteel4OfflineCur(steelPlate);
                    }

                    resetStepFlag=false;
                    log.info("用户{}启动了半自动步骤2，任务存在，天车编号{},任务类型{}", ShiroUtils.getSessionUserName(), getCraneType(), task.getType()); //type：offline，online
                    //根据任务获取当前任务的所有步骤
                    PublicResult<TaskApart> stepResult = getSemiAutoNowStepBean(2);
                    //如果生成成功,分配任务准备执行
                    if (stepResult.isSuccess()) {
                        //修改工作状态
                        WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                        workStatus.setNowTask("半自动");
                        workStatus.setNowMode(task.getType());
                        taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);

                        TaskApart taskApart = stepResult.getData();
                        taskApart.setTaskApartByTask(task);
                        taskApart.action();
                    }
                    //调试suck多块板用，开始
                    /*if("offline".equals(task.getType())){
                        int steelsCount=3;
                        for (int i=0;i<steelsCount;i++){
                            Roller roller=rollerService.queryById(task.getRollerId());
                            Boolean nextReady= Boolean.parseBoolean(plcOperator.readValueByLabel(roller.getReadySignal()));
                            while (!nextReady){
                                nextReady= Boolean.parseBoolean(plcOperator.readValueByLabel(roller.getReadySignal()));
                            }
                            //String steel_num = plcOperator.readPoint(WorkConst.getRollerSteelNumSignal(roller.getId())); //获取钢板号
                            String steel_num ="123";
                            //        TODO:从MES查询钢板信息
                            SteelPlate steel2Suck=new SteelPlate();  //假如从mes获取的
                            String lastSteelType=(String) taskRedisApi.get(getCraneType()+"_steelType");
                            if(lastSteelType.equals(steel2Suck.getSteelType())){
                                task.setSteelNum(steel2Suck.getSteelId());
                                task.setSteelType(steel2Suck.getSteelType());
                                taskRedisApi.set(getCraneType()+"_steelType",task.getSteelType());

                                Task task4Z= WorkConst.cacheTaskMap.get(task.getCraneType()+"_task");
                                if(task4Z!=null){
                                    List<SteelPlate> steels4Z= task4Z.getSteels4Offline();
                                    steels4Z.add(steel2Suck);
                                    WorkConst.cacheTaskMap.put(task.getCraneType()+"_task",task4Z);
                                }else{
                                    List<SteelPlate> steels4Z=new ArrayList<>();
                                    steels4Z.add(steel2Suck);
                                    task.setSteels4Offline(steels4Z);
                                    WorkConst.cacheTaskMap.put(task.getCraneType()+"_task",task);
                                }
                                PublicResult<TaskApart> stepResult2 = getSemiAutoNowStepBean(2);
                                //如果生成成功,分配任务准备执行
                                if (stepResult2.isSuccess()) {
                                    TaskApart taskApart = stepResult2.getData();
                                    taskApart.setTaskApartByTask(task);
                                    taskApart.action();
                                }
                            }else{
                                break;
                            }
                        }

                    }*/
                    //调试suck多块板用，结束
                    //taskService.saveOrUpdate(task);
                    taskStatus.setTaskStatusByCraneType(getCraneType(), "");
                    taskStatus.setWorkModeByCraneType(getCraneType(), "");
                }catch (Exception e) {
                    resetStepFlag=true;
                    log.error(e.getMessage(),e);
                    e.printStackTrace();
                    log.debug("suck2 resetStepFlag=true");
                }
                finally {
                    if(!resetStepFlag){
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=3;
                    }else {
                        log.info("suck2 resetStepFlag生效");
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=0;
                    }
                }
            };

            setNowThread(craneSemiAutoWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneSemiAutoWorkRunnable);
            return PublicResult.ok("启动成功");
        }
        return PublicResult.fail(result.getMsg());
    }

    @Override
    public PublicResult move3() {

        PublicResult result = checkNowStepAndIsHelp(3);
        if (result.isSuccess()) {
            this.semiAutoRunFlag = true;
            Runnable craneSemiAutoWorkRunnable = () -> {
                boolean resetStepFlag=true;
                try {
                    if(!taskRedisApi.hasKey(getCraneType()+"_taskId")){
                        log.info("{}天车，用户{}执行半自动步骤3，缓存中无任务id，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                        this.semiAutoRunFlag =false;
                        this.semiAutoNowStep=0;
                        return;
                    }
                    Integer taskId=(Integer) taskRedisApi.get(getCraneType()+"_taskId");
                    Task task= taskService.queryById(taskId);
                    if(task==null){
                        log.info("{}天车，用户{}执行半自动步骤3，数据库中无当前任务，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                        this.semiAutoRunFlag =false;
                        this.semiAutoNowStep=0;
                        return;
                    }
                    resetStepFlag=false;
                    //根据任务获取当前任务的所有步骤
                    PublicResult<TaskApart> stepResult = getSemiAutoNowStepBean(3);
                    //如果生成成功,分配任务准备执行
                    if (stepResult.isSuccess()) {
                        //修改工作状态
                        WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                        workStatus.setNowTask("半自动");
                        workStatus.setNowMode(task.getType());
                        taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);

                        TaskApart taskApart = stepResult.getData();
                        taskApart.setTaskApartByTask(task);
                        taskApart.action();
                    }
                    taskStatus.setTaskStatusByCraneType(getCraneType(), "");
                    taskStatus.setWorkModeByCraneType(getCraneType(), "");
                }catch (Exception e) {
                    resetStepFlag=true;
                    log.error(e.getMessage(),e);
                    e.printStackTrace();
                    log.debug("move3 resetStepFlag=true");
                }
                finally {
                    if(!resetStepFlag){
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=4;
                    }else {
                        log.info("move3 resetStepFlag生效");
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=0;
                    }
                }
            };

            setNowThread(craneSemiAutoWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneSemiAutoWorkRunnable);
            return PublicResult.ok("启动成功");
        }
        return PublicResult.fail(result.getMsg());
    }

    @Override
    public PublicResult place4() {

        PublicResult result = checkNowStepAndIsHelp(4);
        if (result.isSuccess()) {
            this.semiAutoRunFlag = true;
            Runnable craneSemiAutoWorkRunnable = () -> {
                try {
                    if(!taskRedisApi.hasKey(getCraneType()+"_taskId")){
                        log.info("{}天车，用户{}执行半自动步骤4，缓存中无任务id，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                        this.semiAutoRunFlag =false;
                        this.semiAutoNowStep=0;
                        return;
                    }
                    Integer taskId=(Integer) taskRedisApi.get(getCraneType()+"_taskId");
                    Task task= taskService.queryById(taskId);
                    if(task==null){
                        log.info("{}天车，用户{}执行半自动步骤4，数据库中无当前任务，状态重置后退出该步骤线程。",getCraneType(),ShiroUtils.getSessionUserName());
                        this.semiAutoRunFlag =false;
                        this.semiAutoNowStep=0;
                        return;
                    }
                    //根据任务获取当前任务的所有步骤
                    PublicResult<TaskApart> stepResult = getSemiAutoNowStepBean(4);
                    //如果生成成功,分配任务准备执行
                    if (stepResult.isSuccess()) {
                        //修改工作状态
                        WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                        workStatus.setNowTask("半自动");
                        workStatus.setNowMode(task.getType());
                        taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);

                        TaskApart taskApart = stepResult.getData();
                        taskApart.setTaskApartByTask(task);
                        taskApart.action();
                    }
                    task.setEndTime(new Date());
                    taskService.saveOrUpdate(task);
                    taskStatus.setTaskStatusByCraneType(getCraneType(), "");
                    taskStatus.setWorkModeByCraneType(getCraneType(), "");
                }catch (Exception e) {
                    log.error(e.getMessage(),e);
                    e.printStackTrace();
                }
                finally {
                    taskRedisApi.del(getCraneType()+"_taskId");
                    taskRedisApi.del(getCraneType()+"_steelType");
                    taskRedisApi.set(getCraneType()+"_status",0);  //天车故障，自动任务中断，半自动任务收场，收场后将缓存中天车状态置正常
                    this.semiAutoRunFlag = false;
                    this.semiAutoNowStep=0;
                }
            };

            setNowThread(craneSemiAutoWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneSemiAutoWorkRunnable);
            return PublicResult.ok("启动成功");
        }
        return PublicResult.fail(result.getMsg());
    }

    public boolean isRemoteAutoMode() throws Exception {
        String mode= HttpPLCUtils.plcReadbc(restTemplate,serverHost,getCraneType(),"模式",false);
        if(!"5".equals(mode)){
            log.info("天车：{},监听到模式不为远程自动，当前模式为：{}",getCraneType(),mode);
            return false;
        }
        return true;
    }

    @Override
    public PublicResult startWork(Integer sheetNumber) {    //吸多块钢板的启动自动任务
        PublicResult result = checkPostWorkCondition();
        if (result.isSuccess()) {
            this.startLogo = true;

            Runnable craneWorkRunnable = () -> {
                try {
                    //当标志位为true时，持续执行任务
                    while (startLogo) {
                        if(!isRemoteAutoMode()){
                            startLogo=false;
                            taskStatus.setUnnormalByCraneType(getCraneType(),"天车被切换到非远程自动模式，被迫停止自动");
                            log.info("天车【{}】被切换到非远程自动模式，被迫停止自动",this.getCraneType());
                            break;
                        }
                        //生成任务
                        Task task = getCraneTask(sheetNumber);

                        if (task != null) {
                            task.setTaskType("auto");
                            //设置任务开始时间
                            task.setBeginTime(new Date());
                            task = taskService.insert(task);
                            //此两个redis缓存，为了当自动任务中断，要半自动收场，提供任务信息
                            taskRedisApi.set(getCraneType()+"_taskId",task.getId());

                            //根据任务获取当前任务的所有步骤
                            PublicResult<List<TaskApart>> stepResult = getStepsByTask(task, sheetNumber);

                            //如果生成成功,分配任务准备执行
                            if (stepResult.isSuccess()) {

                                //修改工作状态
                                WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                                workStatus.setNowTask("自动");
                                workStatus.setNowMode(task.getType());
                                taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);
                                //多板模式钢板数量
                                HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,getCraneType(),"DB20.4",HttpPLCUtils.dataTypeList.get("int16"),sheetNumber+"","多板模式钢板数量",false);
                                //写入多板模式
                                HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,getCraneType(),"DB20.6",HttpPLCUtils.dataTypeList.get("bool"),"TRUE","多板模式",false);
                                List<TaskApart> taskApartList = stepResult.getData();
                                int apartNum=0;
                                for (TaskApart taskApart : taskApartList) {
                                    apartNum++;
                                    String crane=getCraneType();
                                    SteelPlate steelInfo=new SteelPlate();
                                    if("suck".equals(taskApart.getType())&&apartNum>1){  //跳过第一次
                                        Roller roller=rollerService.queryById(task.getRollerId());

                                        String isSelected="";
                                        if(!"3#横移".equals(crane)){
                                            //判断一级辊道上PLC选择哪台车下料
                                            isSelected = HttpPLCUtils.plcReadbc(restTemplate, serverHost, crane, roller.getSelectSignal(), true);
                                            //isSelected="true";
                                            while(!"true".equalsIgnoreCase(isSelected)){
                                                log.info("{}天车一级辊道选择信号为False",getCraneType());
                                                isSelected = HttpPLCUtils.plcReadbc(restTemplate, serverHost, crane, roller.getSelectSignal(), true);
                                            }
                                        }
                                        //读取一级辊道允许信号
                                        String isAllow= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getAllowSignal(),true);
                                        //isAllow="true";
                                        long start = System.currentTimeMillis();
                                        while(!"true".equalsIgnoreCase(isAllow)){
                                            log.info("{}天车多板任务模式一级辊道允许起吊信号为False",getCraneType());
                                            isAllow= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getAllowSignal(),true);
                                            if(System.currentTimeMillis() - start > GlobalConstant.MULT_STEEL_WAIT_SECOND * 1000){
                                                log.warn("{}天车多板任务模式等待下块钢板超时",getCraneType());
                                                taskStatus.setUnnormalByCraneType(getCraneType(),"多板任务模式等待下块钢板超时");
                                                return;
                                            }

                                        }
                                        //获取一级辊道钢板号
                                        String steelNo = HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getSteelSignal(),true); //获取钢板号
                                        //steelNo="25214120";
                                        log.info("{}天车获取辊道PLC上钢板号为：{}",crane,steelNo);
                                        String steelNo2="";
                                        if(!"0".equals(steelNo)&& StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7){
                                            steelNo2= StaticMethod.updateSteelNo(crane,steelNo);
                                            List<SteelInfo> steels= steelInfoService.selectByMatNo(steelNo2);
                                            //List<Test> steels= testService.selectByMatNo(steelNo2);
                                            if(steels!=null&&steels.size()==1){
                                                log.info("{}天车第一次查询MES数据库中有此钢板号{}",getCraneType(),steelNo2);
                                                taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板号"+steelNo);
                                                isSteelInfoChecked=true;
                                                steelInfoWrite.setSteelId(steelNo2);
                                            } else if (steels!=null&&steels.size()>1) {
                                                String selectedSteelNo=StaticMethod.autoSelectCurMonthSteelNo(steels,steelNo2,getCraneType());
                                                if(selectedSteelNo.equals(steelNo2)){
                                                    log.info("{}天车第一次查询MES数据库中有多条此钢板号{}信息",getCraneType(),steelNo2);
                                                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条此钢板号"+steelNo2+"信息,更正");
                                                    isSteelInfoChecked=false;
                                                }else{
                                                    log.info("{}天车第一次查询MES数据库中有多条,默认选择此钢板号{}",getCraneType(),selectedSteelNo);
                                                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条，默认选此钢板号"+selectedSteelNo);
                                                    isSteelInfoChecked=true;
                                                    steelInfoWrite.setSteelId(selectedSteelNo);
                                                }

                                            } else{
                                                log.info("{}天车第一次查询MES数据库中无此钢板号{}",getCraneType(),steelNo2);
                                                taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中无此钢板号"+steelNo+"，更正");
                                                isSteelInfoChecked=false;
                                            }
                                        }else {
                                            taskStatus.setUnnormalByCraneType(getCraneType(),"一级辊道钢板号错误，为："+steelNo+"，更正");
                                            isSteelInfoChecked=false;
                                        }
                                        taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo);  //设置界面上显示的钢板号
                                        while (!isSteelInfoChecked){   //等待界面确认或更正钢板信息
                                            if(!startLogo){
                                                break;
                                            }
                                            //log.info("等待输入1等待输入1等待输入1等待输入1等待输入1");
                                            Thread.sleep(200);
                                        }
                                        String steelNo3= steelInfoWrite.getSteelId();
                                        if(StringUtils.isNotEmpty(steelNo2)&&!steelNo2.equals(steelNo3)){
                                            if(StringUtils.isEmpty(steelNo3)){   //只输入了长宽厚，没有钢板号
                                                taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo);  //设置界面上显示的钢板号
                                            }else {
                                                taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo3);  //设置界面上显示的钢板号
                                            }

                                        }else if(StringUtils.isEmpty(steelNo3)){
                                            taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo);  //设置界面上显示的钢板号
                                        } else if (StringUtils.isEmpty(steelNo2)) { //一级辊道获取的钢板号错误
                                            taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo3);  //设置界面上显示的钢板号
                                        }
                                        //SteelInfo steel= steelInfoService.selectByMatNo(ocrRe.getResult());
                                        if(StringUtils.isEmpty(steelNo3)){
                                            if(StringUtils.isNotEmpty(steelNo2)){
                                                steelNo3=steelNo2;
                                            }else {
                                                steelNo3=steelNo;
                                            }
                                        }
                                        List<SteelInfo> steelList= steelInfoService.selectByMatNo(steelNo3);
                                        //List<Test> steelList= testService.selectByMatNo(steelNo3);
                                        if(steelList==null||(steelList!=null&&steelList.size()==0)){
                                            taskStatus.setUnnormalByCraneType(getCraneType(),"无钢板信息，采用录入长宽厚");
                                            log.error("{}天车MES数据库中无此钢板号{},采用录入长宽厚信息",getCraneType(),steelNo3);
                                            steelInfo=steelInfoWrite;
                                        }else if(steelList!=null&&steelList.size()>1){
                                            taskStatus.setUnnormalByCraneType(getCraneType(),"有多条钢板信息，采用录入长宽厚");
                                            log.error("{}天车MES数据库中有多条此钢板号{}信息,采用录入长宽厚信息",getCraneType(),steelNo3);
                                            steelInfo=steelInfoWrite;
                                        }else if(steelList!=null&&steelList.size()==1){
                                            taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板信息，可采用");
                                            log.info("{}天车第二次查询MES数据库中有此钢板号{}，可采用",getCraneType(),steelNo3);
                                            steelInfo=new SteelPlate();
                                            if("11C南".equals(crane)||"11C北".equals(crane)) {
                                                String combStr=StaticMethod.getYearAndMonthJoin();
                                                if(StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&(steelNo3.equals(steelNo2)||(steelNo3.length()==11&&steelNo3.startsWith(combStr)))){
                                                    steelInfo.setSteelId(steelNo);
                                                    String length= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,"dj2dj3钢板长度",true);
                                                    log.info("{}天车从一级辊道PLC获取钢板长度为{}",crane,length);
                                                    steelInfo.setLength(Math.round(Float.parseFloat(length)*1000));
                                                }else{
                                                    steelInfo.setSteelId(steelList.get(0).getMatNo());
                                                    steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                                                }
                                            }else {
                                                steelInfo.setSteelId(steelList.get(0).getMatNo());
                                                steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                                            }
                                            steelInfo.setWidth(Math.round(steelList.get(0).getMatActWidth()));
                                            steelInfo.setThickness(Math.round(steelList.get(0).getMatActThick()));
                                            steelInfo.setWeight(Math.round(steelList.get(0).getMatActWt()));
                                        }
                                        //todo 修改钢板信息
                                        task.setSteelNo(steelNo3);
                                        if(StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&steelNo2.equals(steelNo3)){
                                            task.setSteelNo(steelNo);
                                        } else if (StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&!steelNo2.equals(steelNo3)) {
                                            task.setSteelNo(steelNo3);
                                        } else if (StringUtils.isNotEmpty(steelNo)&&steelNo.length()<7) {
                                            task.setSteelNo(steelNo3);
                                        }else {
                                            task.setSteelNo(steelNo);
                                        }
                                        if(StringUtils.isEmpty(steelInfo.getSteelId())){
                                            steelInfo.setSteelId(task.getSteelNo());
                                        }
                                        String[] lockArr= roller.getLockSignal().split("-");
                                        //写一级辊道锁定信号
                                        HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,crane,lockArr[1],HttpPLCUtils.dataTypeList.get("bool"),"TRUE",lockArr[0],true);
                                        //向天车写辊道锁定信息信号
                                        HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,crane,"DB20.10",HttpPLCUtils.dataTypeList.get("bool"),"TRUE","辊道锁定",false);

                                        //if(!steels.get(0).getSteelType().equals(steel2Suck.getSteelType())){  //TODO 如果钢板长宽厚与上次不一样，则place
                                        if(false){
                                            for(int i=0;i<taskApartList.size();i++){
                                                if("place".equals(taskApartList.get(i).getType())){
                                                    taskApartList.get(i).setTaskApartByTask(task);
                                                    taskApartList.get(i).action();
                                                    task.setEndTime(new Date());
                                                    taskService.saveOrUpdate(task);
                                                    taskStatus.setTaskStatusByCraneType(getCraneType(), "");
                                                    taskStatus.setWorkModeByCraneType(getCraneType(),"");
                                                    return;
                                                }
                                            }
                                        }
                                        List<SteelPlate> steelPlates=task.getSteels4Offline();
                                        steelPlates.add(steelInfo);
                                        task.setSteels4Offline(steelPlates);
                                        task.setSteel4OfflineCur(steelInfo);
                                    }
                                    taskApart.setTaskApartByTask(task);
                                    if("place".equals(taskApart.getType())||"place-roller".equals(taskApart.getType())){
                                        boolean isSucked=plcOperator.checkIsSuckedSteel(getCraneType());
                                        if(isSucked){
                                            taskApart.action();
                                        }else{
                                            taskStatus.setUnnormalByCraneType(getCraneType(),"吸板步骤异常，未吸板放弃放板步骤");
                                            log.info("天车{}自动任务吸板步骤异常，未吸板放弃放板步骤",getCraneType());
                                        }
                                    }else {  //吸板步骤的情况
                                        boolean isSucked=plcOperator.checkIsSuckedSteel(getCraneType());
                                        if(isSucked&&apartNum==1){
                                            startLogo=false;
                                            taskStatus.setUnnormalByCraneType(getCraneType(),"吸第一块前检测到吊具有板，退出自动任务");
                                            log.info("天车{}自动任务多板模式吸板步骤吸第一块前检测到吊具有板，放弃吸板步骤",getCraneType());
                                            return;
                                        }else{
                                            taskApart.action();
                                        }
                                    }
                                }
                            }
                        }
                        //删除此两个redis缓存，为了当自动任务中断，要半自动收场，不会提供错误信息
                        taskRedisApi.del(getCraneType()+"_taskId");
                    }
                } catch (Exception e) {
                    startLogo=false;
                    if(e.getMessage() != null &&e.getMessage().length() > 300){
                        taskStatus.setUnnormalByCraneType(getCraneType(),e.getMessage().substring(0,300));
                    } else {
                        taskStatus.setUnnormalByCraneType(getCraneType(),e.getMessage());
                    }
                    log.error(e.getMessage(),e);
                    e.printStackTrace();

                }
            };

            setNowThread(craneWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneWorkRunnable);
            return PublicResult.ok("启动成功");
        }
        return result;
    }



    @Override
    public Task getCraneTask(int steelNum2Suck) throws Exception {
        if(plcOperator.upperCraneIsEnter(getCraneType())){
            try {
                taskStatus.setUnnormalByCraneType(getCraneType(),"上层行车闯入，自动任务暂停");
                Thread.sleep(1000);
                return null;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        if(plcOperator.personIsEnter(getCraneType())){
            try {
                taskStatus.setUnnormalByCraneType(getCraneType(),"门禁有人员闯入，自动任务暂停");
                Thread.sleep(1000);
                return null;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        Task task = getNormalTask(steelNum2Suck);
        if (task != null) {
            if("online".equals(task.getType())){
              task=move2TakePhotoAndHandleOCR(task);  //移动到垛位上方，获取拍照OCR识别后的钢板信息
            }
            return task;
        }else {
            return null;
        }
        /*else {             //停泊待定
            return getBackTask();
        }*/
    }

    public Task getBackTask() {
        //创建新的Task任务
        Task task = new Task();
        String crane = getCraneType();
        //获取天车配置
        CraneInfo craneInfo = craneInfoService.queryByName(crane);

        //根据天车配置，设定工作类型
        task.setType("move");

        //设置天车编号
        task.setCraneType(crane);

        return task;
    }

    public Task getNormalTask(int steelNum2Suck) throws Exception {

        try {
            //创建新的Task任务
            Task task = new Task();
            String crane = getCraneType();
            taskStatus.setUnnormalByCraneType(getCraneType(),"");
            //获取天车配置
            CraneInfo craneInfo = craneInfoService.queryByName(crane);

            //根据天车配置，设定工作类型
            task.setType("offline");
            if (craneInfo.getWorkMode() != 0) {
                task.setType("online");
            }

            //设置天车编号
            task.setCraneType(crane);


            List<Integer> craneIds = new ArrayList<>();
            craneIds.add(craneInfo.getId());
            //查询辊道信息
            List<Roller> rollers = rollerService.selectRollerByCraneId(craneIds);
            if (rollers.size() == 0) {
                log.error("没有找到对应的辊道");
                return null;
            }


            //构建辊道库存位位，Map
            Map<Roller, List<Stock>> rollerMap = new HashMap<>();
            SteelPlate steelInfo=null;//从mes中获取的钢板信息
            //查询辊道条件，确定能否上下料
            if (task.getType().equals("offline")) {
                for (Roller roller : rollers) {
                    //判断垛位上钢板数量是否等于界面设置的堆放张数
                    //int steelsNum =getStockSteelsNumberByRoller(roller);
                    if(suckedNum>=stockPlaceNumber){
                        //呼叫上层行车运走垛位上钢板
                        if("1".equals(stockNo)){
                            HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,crane,"DB20.9.1",HttpPLCUtils.dataTypeList.get("bool"),"TRUE","上层行车呼叫1",false);
                        }else{
                            HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,crane,"DB20.9.2",HttpPLCUtils.dataTypeList.get("bool"),"TRUE","上层行车呼叫2",false);
                        }
                        log.info("{}天车对应的垛位钢板数量已达到设定值：{}，已呼叫上层行车",getCraneType(),stockPlaceNumber);
                        updateSteelPlatesInStockByRoller(roller);
                        this.startLogo=false;
                        taskStatus.setUnnormalByCraneType(getCraneType(),"垛位钢板数已达设定值，已呼叫上层行车");
                        Thread.sleep(5000);
                        return null;
                    }
                    String isSelected="";
                    if(!"3#横移".equals(crane)){
                        //判断一级辊道上PLC选择哪台车下料
                        isSelected = HttpPLCUtils.plcReadbc(restTemplate, serverHost, crane, roller.getSelectSignal(), true);
                        log.info("天车【{}】获取任务时，一级辊道上PLC选择信号：{},读取出来的值为：{}",this.getCraneType(),roller.getSelectSignal(),isSelected);

                        //isSelected="true";
                        if(!"true".equalsIgnoreCase(isSelected)){
                            //log.info("{}天车一级辊道选择信号为False",getCraneType());
                            return null;
                        }
                    }
                    //读取一级辊道允许信号
                    String isAllow= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getAllowSignal(),true);
                    //isAllow="true";
                    log.info("天车【{}】获取任务时，对应辊道允许信号为：{}",this.getCraneType(),isAllow);
                    if(!"true".equalsIgnoreCase(isAllow)){
                        //log.info("{}天车一级辊道允许起吊信号为False",getCraneType());
                        return null;
                    }
                    //获取一级辊道钢板号
                    String steelNo = HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getSteelSignal(),true); //获取钢板号
                    //steelNo="25214120";
                    log.info("{}天车获取辊道PLC上钢板号为：{}",crane,steelNo);
                    String steelNo2="";
                    Boolean indexSteelNoFlag = false;
                    if("0".equals(steelNo)){
                        taskStatus.setUnnormalByCraneType(getCraneType(),"钢板号为0,不能生成任务");
                        isSteelInfoChecked=false;
                        while (!isSteelInfoChecked){
                            //等待页面输入钢板号
                            log.info("天车：{}，PLC读取钢板号为0，取页面输入的钢板号",crane);
                            indexSteelNoFlag = true;
                            steelNo = steelInfoWrite.getSteelId();
                            boolean modeFlag = isRemoteAutoMode();
                            if(!modeFlag){
                                startLogo=false;
                                log.info("天车:{}等待页面输入钢板号时,模式切到非远程自动模式",crane);
                                taskStatus.setUnnormalByCraneType(getCraneType(),"天车被切换到非远程自动模式，被迫停止自动");
                                return null;
                            }
                            String taskFlag = HttpPLCUtils.plcReadbc(restTemplate, serverHost, getCraneType(), "任务中止", false);
                            if("true".equalsIgnoreCase(taskFlag)){
                                log.info("天车:{}等待页面输入钢板号时，监听到任务中止信号",crane);
                                throw new TaskRunningException("任务人工停止",getCraneType());
                            }

                            Thread.sleep(1000);
                        }
                    }
                    if(!"0".equals(steelNo)&& StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7){

                        if(indexSteelNoFlag){
                            //若页面进行修改，则取页面修改的钢板号
                            isSteelInfoChecked=true;
                            steelNo2 = steelNo;
                        } else {
                            boolean specialsteelnoflag = false;
                            if("5#横移".equals(crane) || "4#横移".equals(crane) || "3#横移".equals(crane)){
                                specialsteelnoflag = Boolean.valueOf(HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,StaticMethod.getSpecialSteelNoFlagLabel(crane),true));
                                log.info("{}天车读出来的是否需要规则转换出来的信号是：{}", crane, specialsteelnoflag);

                            }
                            steelNo2= StaticMethod.updateSteelNo(crane,steelNo,specialsteelnoflag);
                            log.info("{}天车系统根据规则转换出来的钢板号是：{}", crane, steelNo2);
                        }
                        List<SteelInfo> steels= steelInfoService.selectByMatNo(steelNo2);
                        //todo 代码调式
//                        List<Test> tests= testService.selectByMatNo(steelNo2);
//                        List<SteelInfo> steels = new ArrayList<>();
//
//                        Test test = tests.get(0);
//                        SteelInfo build = SteelInfo.builder().matActThick(test.getMatActThick()).matActWidth(test.getMatActWidth()).matActWt(test.getMatActWt())
//                                .matNo(test.getMatNo()).matActLen(test.getMatActLen()).build();
//                        steels.add(build);

                        if(steels!=null&&steels.size()==1){
                            log.info("{}天车第一次查询MES数据库中有此钢板号{}",getCraneType(),steelNo2);
                            taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板号"+steelNo2);
                            isSteelInfoChecked=true;
                            steelInfoWrite.setSteelId(steelNo2);
                        } else if (steels!=null&&steels.size()>1) {
                            String selectedSteelNo=StaticMethod.autoSelectCurMonthSteelNo(steels,steelNo2,getCraneType());
                            if(selectedSteelNo.equals(steelNo2)){
                                if(!("11C南".equals(crane)||"11C北".equals(crane))){
                                    List<SteelInfo> steelsTemp=new ArrayList<>();
                                    steelsTemp.add(steels.get(0));
                                    steels=steelsTemp;
                                    log.info("{}天车第一次查询MES数据库中有多条,默认选择第一条记录",getCraneType());
                                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条，默认选择第一条记录");
                                    isSteelInfoChecked=true;
                                    steelInfoWrite.setSteelId(selectedSteelNo);
                                }else {
                                    log.info("{}天车第一次查询MES数据库中有多条此钢板号{}信息",getCraneType(),steelNo2);
                                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条此钢板号"+steelNo2+"信息,更正");
                                    isSteelInfoChecked=false;
                                }

                            }else{
                                log.info("{}天车第一次查询MES数据库中有多条,默认选择此钢板号{}",getCraneType(),selectedSteelNo);
                                taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条，默认选此钢板号"+selectedSteelNo);
                                isSteelInfoChecked=true;
                                steelInfoWrite.setSteelId(selectedSteelNo);
                            }

                        } else{
                            log.info("{}天车第一次查询MES数据库中无此钢板号{}",getCraneType(),steelNo2);
                            taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中无此钢板号"+steelNo2+"，更正");
                            isSteelInfoChecked=false;
                        }
                    }else {
                        taskStatus.setUnnormalByCraneType(getCraneType(),"一级辊道钢板号错误，为："+steelNo+"，更正");
                        isSteelInfoChecked=false;
                    }
                    taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo);  //设置界面上显示的钢板号
                    while (!isSteelInfoChecked){   //等待界面确认或更正钢板信息
                        if(!(startLogo||semiAutoRunFlag)){
                            return null;
                        }
                        //log.info("等待输入1等待输入1等待输入1等待输入1等待输入1");
                        Thread.sleep(200);
                    }
                    String steelNo3= steelInfoWrite.getSteelId();
                    taskStatus.setSteelStatusByCraneType(getCraneType(),steelNo3);  //设置界面上显示的钢板号

                    //SteelInfo steel= steelInfoService.selectByMatNo(ocrRe.getResult());
                    if(StringUtils.isEmpty(steelNo3)){
                        if(StringUtils.isNotEmpty(steelNo2)){
                            steelNo3=steelNo2;
                        }else {
                            steelNo3=steelNo;
                        }
                    }
                    List<SteelInfo> steelList= steelInfoService.selectByMatNo(steelNo3);
                    //todo 代码调式
//                    List<SteelInfo> steelList= new ArrayList<>();
//                    List<Test> testList = testService.selectByMatNo(steelNo3);
//                    Test test = testList.get(0);
//                    SteelInfo build = SteelInfo.builder().matActThick(test.getMatActThick()).matActWidth(test.getMatActWidth()).matActWt(test.getMatActWt())
//                            .matNo(test.getMatNo()).matActLen(test.getMatActLen()).build();
//                    steelList.add(build);

                    if(steelList==null||(steelList!=null&&steelList.size()==0)){
                        taskStatus.setUnnormalByCraneType(getCraneType(),"无钢板信息，采用录入长宽厚");
                        log.error("{}天车MES数据库中无此钢板号{},采用录入长宽厚信息",getCraneType(),steelNo3);
                        steelInfo=steelInfoWrite;
                    }else if(steelList!=null&&steelList.size()>1){
                        if(!("11C南".equals(crane)||"11C北".equals(crane))) {
                            steelInfo=new SteelPlate();
                            steelInfo.setSteelId(steelList.get(0).getMatNo());
                            steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                            steelInfo.setWidth(Math.round(steelList.get(0).getMatActWidth()));
                            steelInfo.setThickness(Math.round(steelList.get(0).getMatActThick()));
                            steelInfo.setWeight(Math.round(steelList.get(0).getMatActWt()));
                            taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条,默认选择第一条记录");
                            log.info("{}天车第二次查询MES数据库中有多条,默认选择第一条记录",getCraneType());
                        }else {
                            taskStatus.setUnnormalByCraneType(getCraneType(),"有多条钢板信息，采用录入长宽厚");
                            log.error("{}天车MES数据库中有多条此钢板号{}信息,采用录入长宽厚信息",getCraneType(),steelNo3);
                            steelInfo=steelInfoWrite;
                        }

                    }else if(steelList!=null&&steelList.size()==1){
                        taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板信息，可采用");
                        log.info("{}天车第二次查询MES数据库中有此钢板号{}，可采用",getCraneType(),steelNo3);
                        steelInfo=new SteelPlate();
                        if("11C南".equals(crane)||"11C北".equals(crane)) {
                            String combStr=StaticMethod.getYearAndMonthJoin();
                            if(StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&(steelNo3.equals(steelNo2)||(steelNo3.length()==11&&steelNo3.startsWith(combStr)))){
                                steelInfo.setSteelId(steelNo);
                                String length= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,"dj2dj3钢板长度",true);
                                log.info("{}天车从一级辊道PLC获取钢板长度为{}",crane,length);
                                steelInfo.setLength(Math.round(Float.parseFloat(length)*1000));
                            }else{
                                steelInfo.setSteelId(steelList.get(0).getMatNo());
                                steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                            }
                        }else {
                            steelInfo.setSteelId(steelList.get(0).getMatNo());
                            steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                        }
                        steelInfo.setWidth(Math.round(steelList.get(0).getMatActWidth()));
                        steelInfo.setThickness(Math.round(steelList.get(0).getMatActThick()));
                        steelInfo.setWeight(Math.round(steelList.get(0).getMatActWt()));
                    }
                    if(StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&steelNo2.equals(steelNo3)){
                        task.setSteelNo(steelList.get(0).getMatNo());
                    } else if (StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&!steelNo2.equals(steelNo3)) {
                        task.setSteelNo(steelList.get(0).getMatNo());
                    } else if (StringUtils.isNotEmpty(steelNo)&&steelNo.length()<7) {
                        task.setSteelNo(steelList.get(0).getMatNo());
                    }else {
                        task.setSteelNo(steelList.get(0).getMatNo());
                    }
                    log.info("得到的task任务的钢板号为：{}",task.getSteelNo());
                    if(StringUtils.isEmpty(steelInfo.getSteelId())){
                        steelInfo.setSteelId(task.getSteelNo());
                    }


                    //20250718   modify by zhangwei   钢板尺寸检验不通过时，允许手动输入信息
                    isSteelInfoChecked = StaticMethod.checkSteelInfo(steelInfo);
                    taskStatus.setSteelStatusByCraneType(getCraneType(),steelInfo.getSteelId());  //设置界面上显示的钢板号

                    taskStatus.setUnnormalByCraneType(getCraneType(),"钢板尺寸检验不通过，请手动输入钢板尺寸信息");
                    steelInfoWrite = new SteelPlate();
                    while (!isSteelInfoChecked){
                        //等待页面输入钢板号
                        log.info("天车：{}，钢板尺寸检验不通过，取页面输入的钢板号",crane);
                        indexSteelNoFlag = true;
                        steelNo = steelInfoWrite.getSteelId();
                        boolean modeFlag = isRemoteAutoMode();
                        if(!modeFlag){
                            startLogo=false;
                            log.info("天车:{}等待页面输入钢板号时,模式切到非远程自动模式",crane);
                            taskStatus.setUnnormalByCraneType(getCraneType(),"天车被切换到非远程自动模式，被迫停止自动");
                            return null;
                        }
                        String taskFlag = HttpPLCUtils.plcReadbc(restTemplate, serverHost, getCraneType(), "任务中止", false);
                        if("true".equalsIgnoreCase(taskFlag)){
                            log.info("天车:{}等待页面输入钢板号时，监听到任务中止信号",crane);
                            throw new TaskRunningException("任务人工停止",getCraneType());
                        }
                        if(isSteelInfoChecked){
                            isSteelInfoChecked = StaticMethod.checkSteelInfo(steelInfoWrite);
                            log.info("天车：{}，钢板尺寸检验再次结果是：{}",crane,isSteelInfoChecked);
                        }
                        Thread.sleep(1000);
                    }
                    taskStatus.setUnnormalByCraneType(getCraneType(),"");

                    String[] lockArr= roller.getLockSignal().split("-");
                    //写一级辊道锁定信号
                    HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,crane,lockArr[1],HttpPLCUtils.dataTypeList.get("bool"),"TRUE",lockArr[0],true);
                    //向天车写辊道锁定信息信号
                    HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,crane,"DB20.10",HttpPLCUtils.dataTypeList.get("bool"),"TRUE","辊道锁定",false);

                    //roller.setSteelInfo4OffLine(steelInfo);
                    //roller.setSteelNum(steelNum2Suck);   //一次task suck的钢板数量
                    List<Stock> stocks = getOfflineReadyStockByRoller(roller);  //判断stock里的钢板总重是否超重
                    if (stocks!=null&&stocks.size() > 0) {
                        rollerMap.put(roller, stocks);
                    } else {
                        log.error("天车{}没有找到合适的垛位",getCraneType());
                        return null;
                    }
                }
                //如果找得到符合条件的辊道和库存位，返回生成的任务
                if (rollerMap.size() > 0) {
                    //设置任务的起始点和终点，如果先遍历直接生成
                    for (Map.Entry<Roller, List<Stock>> entry : rollerMap.entrySet()) {

                        task.setRollerId(entry.getKey().getId());
                        List<SteelPlate> steels=new ArrayList<SteelPlate>();
                        steels.add(steelInfo);
                        task.setSteels4Offline(steels);
                        task.setSteel4OfflineCur(steelInfo);
                        //TODO 是否要判断垛位高度，高于某个值停止任务
                        task.setStockId(entry.getValue().get(0).getId());
                        task.setStockNo(stockNo);
                        return task;
                    }
                }
            } else {
                for (Roller roller : rollers) {
                    if(WorkConst.CRANE_DEBUG_SWITCH_FLAG){
                        log.info("2#车debug开关打开，调过信号逻辑");
                        List<Stock> stocks = getOnlineReadyStockByRoller(roller);  //TODO 判断门禁是否打开，以及垛位是否有钢板
                        if (stocks.size() > 0) {
                            rollerMap.put(roller, stocks);
                        }
                    } else {
                        log.info("2#车debug开关关闭，执行信号逻辑");
                        //读取一级辊道允许信号
                        String isAllow= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getAllowSignal(),true);
                        if("true".equalsIgnoreCase(isAllow)){
                            List<Stock> stocks = getOnlineReadyStockByRoller(roller);  //TODO 判断门禁是否打开，以及垛位是否有钢板
                            if (stocks.size() > 0) {
                                rollerMap.put(roller, stocks);
                            }
                        }else {
                            return null;
                        }
                    }

                }
                //如果找得到符合条件的辊道和库存位，返回生成的任务
                if (rollerMap.size() > 0) {
                    //设置任务的起始点和终点，如果先遍历直接生成
                    for (Map.Entry<Roller, List<Stock>> entry : rollerMap.entrySet()) {
                        //设置起始点为辊道
                        task.setStockId(entry.getValue().get(0).getId());
                        //设置放板点为垛位
                        task.setRollerId(entry.getKey().getZ());
                        return task;
                    }
                }
            }
            return null;
        }catch (Exception ex){
            log.error(ex.getMessage(),ex);
            throw ex;
        }
    }


    public Task move2TakePhotoAndHandleOCR(Task task){
        try{
            //下指令天车移动到垛位上方，
            HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,task.getCraneType(),"DB20.292.5",HttpPLCUtils.dataTypeList.get("bool"),"TRUE","横移车去拍照位",false);
            boolean isMovedOk = false;
            Date startDate=new Date();
            while (!isMovedOk) {  //等待天车移动到垛位上方
                Thread.sleep(50);
                boolean overTime= DateUtils.isOverTimeByNow(startDate,180000);//超过180秒未到位，退出等待。
                if(overTime){
                    isMovedOk=true;
                    log.info(getCraneType()+"等待天车移动到垛位上方拍照超时");
                    taskStatus.setUnnormalByCraneType(task.getCraneType(),"等待天车移动到垛位上方拍照超时");
                    taskRedisApi.set("takePhoto", 1);
                }
                String isFinishStr= HttpPLCUtils.plcReadbc(restTemplate,serverHost,task.getCraneType(),"横移车在拍照位",false);
                if ("true".equalsIgnoreCase(isFinishStr)) {
                    isMovedOk = true;
                    taskRedisApi.set("takePhoto", 1);  //1为到位可以拍照，重置0为未到位
                    //清横移车去拍照位
                    HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,task.getCraneType(),"DB20.292.5",HttpPLCUtils.dataTypeList.get("bool"),"FALSE","横移车去拍照位",false);
                    //清横移车在拍照位
                    HttpPLCUtils.plcWritebcPlus(restTemplate,serverHost,task.getCraneType(),"DB20.292.4",HttpPLCUtils.dataTypeList.get("bool"),"FALSE","横移车在拍照位",false);
                }
            }
            boolean isPhotoedOk = false;
            startDate=new Date();
            while (!isPhotoedOk) {  //等待拍照识别完成
                boolean overTime= DateUtils.isOverTimeByNow(startDate,10000);//超过10秒未出结果，退出等待。
                if(overTime){
                    isPhotoedOk=true;
                    log.info(getCraneType()+"等待拍照识别完成超时");
                    taskStatus.setUnnormalByCraneType(task.getCraneType(),"等待拍照识别完成超时");
                }
                Integer takedOk=(Integer) taskRedisApi.get("isTakedPhoto");
                if (takedOk==1) {
                    isPhotoedOk = true;
                    taskRedisApi.set("isTakedPhoto", 0); //1为OCR识别出结果了，重置0为未识别。
                }
            }
            //String result=HttpUtils.sendGet("Ocr/getResult");  //获取ocr识别出的钢板号
            List<SteelInfo> steels=null;
            try{
                Object res = taskRedisApi.get("result");
                if(res == null){
                    log.error("redis机器无识别数据");
                    throw new Exception("redis机器无识别数据");
                }
                JSONObject result = (JSONObject) res;
                log.info("ocr识别钢板号结果为："+result.toString());
                OcrResult ocrRe= JSON.parseObject(result.toString(), OcrResult.class);
                taskStatus.setNo2ImgSrcByCraneType(getCraneType(),ocrRe.getPicPath(),ocrRe.getResult());
        /*QueryWrapper<SteelPlate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("steel_id", ocrRe.getResult());
        SteelPlate steelOne= steelPlateService.getOne(queryWrapper);*/
                if(StringUtils.isEmpty(ocrRe.getResult())){
                    taskStatus.setUnnormalByCraneType(getCraneType(),"识别出的钢板号为空，请手输入");
                }else {
                    steels= steelInfoService.selectByMatNo(ocrRe.getResult());
                    //List<Test> steels= testService.selectByMatNo(ocrRe.getResult());
                    if(steels!=null&&steels.size()>0){
                        taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板号"+ocrRe.getResult()+",请确认");
                    }else{
                        taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中无此钢板号"+ocrRe.getResult()+",请确认");
                    }
                }

            }catch (Exception ex){
                log.error(ex.getMessage(),ex);
                taskStatus.setUnnormalByCraneType(getCraneType(),"识别出的钢板号为空，请手输入");
            }

            while (!isSteelNoChecked){   //等待界面确认或更正钢板号
                boolean modeFlag = isRemoteAutoMode();
                if(!modeFlag){
                    startLogo=false;
                    log.info("天车:{}等待页面输入钢板号时,模式切到非远程自动模式",getCraneType());
                    taskStatus.setUnnormalByCraneType(getCraneType(),"天车被切换到非远程自动模式，被迫停止自动");
                    return null;
                }
                Thread.sleep(200);
            }
            taskRedisApi.set("result","");
            steels= steelInfoService.selectByMatNo(steelNoUpdated);
            //steels= testService.selectByMatNo(steelNoUpdated);
            log.info("钢板号：{}从数据库查出来数据为：{}",steelNoUpdated,steels.get(0));
            SteelPlate steelOne=null;
            if(steels!=null&&steels.size()>0){
                taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板号"+steelNoUpdated);
                steelOne=new SteelPlate();
                steelOne.setSteelId(steels.get(0).getMatNo());
                steelOne.setLength(Math.round(steels.get(0).getMatActLen()));
                steelOne.setWidth(Math.round(steels.get(0).getMatActWidth()));
                steelOne.setThickness(Math.round(steels.get(0).getMatActThick()));
                steelOne.setWeight(Math.round(steels.get(0).getMatActWt()));
            }else{
                taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中无此钢板号"+steelNoUpdated+",不能生成任务");
                //2号横移钢板号确认恢复初始值
                this.isSteelNoChecked=false;
                this.steelNoUpdated="";
                return null;
            }
            String urlParam="";
            /*if(ocrRe.getResult().equals(steelNoUpdated)){
                urlParam="id="+ocrRe.getId()+"&rightOrWrong=1&realVal="+steelNoUpdated;  //Ocr/sendRightOrWrong?id=78&rightOrWrong=1&realVal=123456789
            }else {//如果OCR识别错误
*//*                QueryWrapper<SteelPlate> queryWrapper2 = new QueryWrapper<>();
                queryWrapper2.eq("area", "stock_" + task.getStockId());
                queryWrapper2.orderByDesc("tier");
                List<SteelPlate> steelPlates = steelPlateService.list(queryWrapper2);*//*
                urlParam="id="+ocrRe.getId()+"&rightOrWrong=0&realVal="+steelNoUpdated;
            }*/

            task.setSteel4Online(steelOne);
            task.setSteelNo(steelOne.getSteelId());
            //String result2=HttpUtils.sendGet("Ocr/sendRightOrWrong?"+urlParam);
            //2号横移钢板号确认恢复初始值
            this.isSteelNoChecked=false;
            this.steelNoUpdated="";
            taskStatus.setSteelStatusByCraneType(this.getCraneType(),steelOne.getSteelId());
            return  task;
        }catch (Exception ex){
            //2号横移钢板号确认恢复初始值
            this.isSteelNoChecked=false;
            this.steelNoUpdated="";
            log.error(ex.getMessage(),ex);
            taskStatus.setUnnormalByCraneType(getCraneType(),ex.getMessage());
            return null;
        }
    }


    /**
     * create by: pzy
     * description: 钢板到位时获取吸取钢板的高度
     * create time: 2023/5/25 14:50
     *
     * @return java.lang.Integer
     * @param: [roller]
     */

    @Override
    public Integer getHeightWhenSteelReady(Roller roller) {
        Integer height =roller.getSteelInfo4OffLine().getThickness();
        return roller.getZ() + height;
    }

    /**
     * create by: pzy
     * description: 获取库存区高度
     * create time: 2023/5/25 14:50
     *
     * @return java.lang.Integer
     * @param: [roller]
     */
    @Override
    public Integer getHeightStock(Stock stock) {
        return stockService.getStockHeightByStockId(stock);
    }


    @Override
    public int updateSteelPlatesInStockByRoller(Roller roller){
        Integer rollerId = roller.getId();
        List<Stock> stocks = stockService.getStocksByRollerIds(rollerId);
        List<Stock> reStocks=new ArrayList<>();
        if (stocks.size() > 0) {
            String craneType=getCraneType();
            if("11C北".equals(craneType)||"11C南".equals(craneType)){
                for(Stock item:stocks){
                    if(item.getName().contains("垛位"+stockNo)){
                        reStocks.add(item);
                    }
                }
            }else {
                reStocks=stocks;
            }
            int num = steelPlateService.updateInStockPlates("stock_" + reStocks.get(0).getId());
            return num;
        }
        return 0;
    }
    @Override
    public int updateSteelPlatesInStockByCrane(String crane){
        CraneInfo craneInfo = craneInfoService.queryByName(crane);
        List<Integer> craneIds = new ArrayList<>();
        craneIds.add(craneInfo.getId());
        List<Roller> rollerList =rollerService.selectRollerByCraneId(craneIds);
        if(rollerList!=null&&rollerList.size()>0){
           return updateSteelPlatesInStockByRoller(rollerList.get(0));
        }
        return 0;
    }

    public int getStockSteelsNumberByRoller(Roller roller){
        Integer rollerId = roller.getId();
        List<Stock> stocks = stockService.getStocksByRollerIds(rollerId);
        List<Stock> reStocks=new ArrayList<>();
        if (stocks.size() > 0) {
            String craneType=getCraneType();
            if("11C北".equals(craneType)||"11C南".equals(craneType)){
                for(Stock item:stocks){
                    if(item.getName().contains("垛位"+stockNo)){
                        reStocks.add(item);
                    }
                }
            }else {
                reStocks=stocks;
            }
            List<SteelPlate> steelPlates = steelPlateService.getAllSteelInStockPlateByArea("stock_" + reStocks.get(0).getId());
            if(steelPlates!=null&&steelPlates.size()>0){
                return steelPlates.size();
            }
        }
        return 0;
    }


    /**
     * create by: pzy
     * description: 根据辊道信息查询适合的下线堆放位
     * create time: 2023/5/25 14:37
     *
     * @return java.util.List<com.tqjc.area.entity.Stock>
     * @param: [roller]
     */
    @Override
    public List<Stock> getOfflineReadyStockByRoller(Roller roller) {   //判断门禁是否打开，判断stock里的钢板总重是否超重
        Integer rollerId = roller.getId();
        List<Stock> stocks = stockService.getStocksByRollerIds(rollerId);
        List<Stock> reStocks=new ArrayList<>();
        if (stocks.size() > 0) {
            String craneType=getCraneType();
            if("11C北".equals(craneType)||"11C南".equals(craneType)){
                for(Stock item:stocks){
                    if(item.getName().contains("垛位"+stockNo)){
                           reStocks.add(item);
                    }
                }
            }else {
                reStocks=stocks;
            }
//            for(Stock item:stocks){          //同一个垛位上放相同规格钢板
//
//            }
            //stocks = checkOkOfflineStocks(stocks,roller.getSteelInfo4OffLine().getWeight()*roller.getSteelNum());
        }

        if(reStocks.size()>0){
            return reStocks;
        }else {
            return null;
        }
    }

    /**
     * create by: pzy
     * description: 根据辊道信息查询适合的上线堆放位
     * create time: 2023/5/25 14:37
     *
     * @return java.util.List<com.tqjc.area.entity.Stock>
     * @param: [roller]
     */
    public List<Stock> getOnlineReadyStockByRoller(Roller roller) {
        Integer rollerId = roller.getId();
        List<Stock> stocks = stockService.getStocksByRollerIds(rollerId);

        if (stocks.size() > 0) {
            //stocks = checkOkOnlineStocks(stocks);
        }

        return stocks;
    }


    /**
     * create by: pzy
     * description: 筛选可以上线的垛位
     * create time: 2023/6/8 16:28
     *
     * @return java.util.List<com.tqjc.area.entity.Stock>
     * @param: [stocks]
     */
    public List<Stock> checkOkOnlineStocks(List<Stock> stocks) {
        List<Stock> readyStocks = new ArrayList<>();
        for (Stock stock : stocks) {
            if (isStockOnlineOk(stock)) {
                readyStocks.add(stock);
            }
        }
        return readyStocks;

    }

    /**
     * create by: pzy
     * description: 筛选可以堆放的垛位
     * create time: 2023/6/8 16:28
     *
     * @return java.util.List<com.tqjc.area.entity.Stock>
     * @param: [stocks]
     */
    public List<Stock> checkOkOfflineStocks(List<Stock> stocks,Integer offlineSteelWeight) {
        List<Stock> readyStocks = new ArrayList<>();
        for (Stock stock : stocks) {
            if (isStockOfflineOk(stock,offlineSteelWeight)) {  //stock里的钢板总重是否超重
                readyStocks.add(stock);
            }
        }
        return readyStocks;

    }

    private boolean isStockOfflineOk(Stock stock,Integer offlineSteelWeight) {
        //判断钢板堆放情况,是否超重
        List<SteelPlate> steelPlates = steelPlateService.getAllSteelPlateByArea("stock_" + stock.getId());
        if (steelPlates.size() > 0) {
            Integer sumWeight = offlineSteelWeight;

            for (SteelPlate steelPlate : steelPlates) {
                sumWeight += steelPlate.getWeight();
            }
            if (sumWeight > WorkConst.MAX_STOCK_WEIGHT) {
                return false;
            }
        }
        return true;
    }

    private boolean isStockOnlineOk(Stock stock) {
        //判断是否被门禁屏蔽
        if (!getIsStockLockByStock(stock)) {
            return false;
        }
        //TODO 钢板怎么入库？判断钢板堆放情况
        List<SteelPlate> steelPlates = steelPlateService.getAllSteelPlateByArea("stock_" + stock.getId());
        if (steelPlates.size() > 0) {
            return true;
        }
        return false;
    }

    private boolean getIsStockLockByStock(Stock stock) {
        return accessControlScheduleTask.getIsStockLockByStockId(stock.getId());
//        return false;
    }


    /**
     * create by: pzy
     * description: 判断当前执行任务的前置工作条件
     * create time: 2023/5/19 15:46
     *
     * @return com.tqjc.execute.utils.PublicResult
     * @param: []
     */
    @Override
    public PublicResult checkPostWorkCondition() {
        if(plcOperator.upperCraneIsEnter(getCraneType())){
            log.info("上层行车已闯入，不能启动任务");
            return PublicResult.fail("上层行车已闯入，不能启动任务");
        }
        if(plcOperator.personIsEnter(getCraneType())){
            log.info("有人员闯入，不能启动任务");
            return PublicResult.fail("有人员闯入，不能启动任务");
        }
        return PublicResult.ok();
    }

    @Override
    public PublicResult checkIsSuckedSteel(){      //必须显示在界面上：天车正处于吸板状态
        try {
            //在停电情况下，如果恢复电后，判断天车是否吸板，如果是吸板，就不让启动。
            String isSucked= HttpPLCUtils.plcReadbc(restTemplate,serverHost,getCraneType(),"吊具有板",false);
            if("true".equalsIgnoreCase(isSucked)){
                return PublicResult.ok();
            }
            return PublicResult.fail("非吸板状态");
        }catch (Exception ex){
            return PublicResult.fail(ex.getMessage());
        }

    }

    @Override
    public PublicResult checkNowStepAndIsHelp(int nowStep) {
        if(plcOperator.upperCraneIsEnter(getCraneType())){
            return PublicResult.fail("上层行车已闯入，目前不能启动该步骤，请稍后再试");
        }
        if(plcOperator.personIsEnter(getCraneType())){
            return PublicResult.fail("有人员闯入，目前不能启动该步骤，请稍后再试");
        }
        if(this.craneStatus!=0){
            return PublicResult.fail("天车有故障，不能启动该步骤，");
        }
        /*if(taskRedisApi.hasKey(getCraneType()+"_status")){  //只有在吸板后出现异常才需要处理，其他情况都可以不用处理
            Integer craneStatus2=(Integer) taskRedisApi.get(getCraneType()+"_status");
            if(craneStatus2!=0){  //天车发生过故障，已经恢复，但并且还未收场，允许半自动操作
                return PublicResult.ok();
            }
        }*/



        if(nowStep==3||nowStep==4){
          //PublicResult result=checkIsSuckedSteel();  //在停电情况下，如果恢复电后，判断天车是否吸板，如果是吸板，就不让启动。如果是正常情况下，也是OK的
          if(!taskRedisApi.hasKey(getCraneType()+"_taskId")){
               Task taskTemp=taskService.getNearestTimeSuckedStatusByCraneType(getCraneType());
               if(taskTemp!=null){
                   taskRedisApi.set(getCraneType()+"_taskId",taskTemp.getId());
                   return PublicResult.ok();
               }else{
                   return PublicResult.fail(getCraneType()+"吸板状态，异常情况不能半自动处理，请用手柄操控");
               }
          }
          return PublicResult.ok();
        }

        return PublicResult.ok();

//        if(this.semiAutoNowStep==0&&nowStep==1){
//            return PublicResult.ok();
//        }else if(this.semiAutoNowStep!=0&&this.semiAutoNowStep==nowStep){
//            return PublicResult.ok();
//        }
//        return PublicResult.fail("不能启动该步骤，请按顺序执行");
    }


    /**
     * create by: pzy获取工作步骤TODO
     * create time: 2023/5/22 9:15
     *
     * @return com.tqjc.execute.utils.PublicResult<java.util.List < com.tqjc.execute.utils.Step>>
     * @param: [task]
     */
    @Override
    public PublicResult<List<TaskApart>> getStepsByTask(Task task) {
        PublicResult<List<String>> stepResult = taskStepService.selectStepsByTaskType(task.getType());
        if (stepResult.isSuccess()) {
            List<TaskApart> taskApars = new ArrayList<>();
            for (String datum : stepResult.getData()) {
                try {
                    //获取对应的对象
                    TaskApart taskApart = SpringUtils.getBean(datum);
                    taskApars.add(taskApart);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return PublicResult.ok(taskApars);
        }
        return null;
    }

    @Override
    public PublicResult<TaskApart> getSemiAutoNowStepBean(int nowStep) {
        try {
            String stepBean="";
            if(nowStep==1){
                stepBean="move1Step";
            }else if(nowStep==2){
                stepBean="suck2Step";
            }else if(nowStep==3){
                stepBean="move3Step";
            }else if(nowStep==4){
                stepBean="place4Step";
            }
            //获取对应的对象
            TaskApart taskApart = SpringUtils.getBean(stepBean);
            return PublicResult.ok(taskApart);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    /**
     * create by: pzy获取多板工作步骤TODO
     * create time: 2023/5/22 9:15
     *
     * @return com.tqjc.execute.utils.PublicResult<java.util.List < com.tqjc.execute.utils.Step>>
     * @param: [task]
     */
    public PublicResult<List<TaskApart>> getStepsByTask(Task task, Integer sheetNumber) {
        PublicResult<List<String>> stepResult = taskStepService.selectStepsByTaskType(task.getType());
        if (stepResult.isSuccess()) {
            List<TaskApart> taskApars = new ArrayList<>();
            List<String> steps = stepResult.getData();
            for (int i = 0; i < steps.size(); i++) {
                try {
                    //生成多个抓取任务
                    if (i == 0) {
                        for (Integer number = sheetNumber; number > 0; number--) {
                            //获取对应的对象
                            TaskApart taskApart = (SpringUtils.getBean(steps.get(i)));
                            //反射创建步骤对象
                            taskApars.add(taskApart);
                        }
                    } else {

                        //获取对应的对象
                        TaskApart taskApart = (SpringUtils.getBean(steps.get(i)));
                        //反射创建步骤对象
//                    TaskApart taskApart = (TaskApart) o;
                        taskApars.add(taskApart);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return PublicResult.ok(taskApars);
        }
        return null;
    }

    /**
     * create by: pzy
     * description: 获取当前正在运行的线程
     * create time: 2023/5/25 16:46
     *
     * @return java.lang.Runnable
     * @param: []
     */
    @Override
    public Runnable getNowThread() {
        return this.nowThread;
    }

    @Override
    public void setNowThread(Runnable runnable) {
        this.nowThread = runnable;

    }

    @Override
    public void startAlign(String craneType){

        AysnAlignThread build = AysnAlignThread.builder().craneWork(this).craneType(this.getCraneType()).host(serverHost).build();
        ThreadPoolManager.getInstance().execute(build);
    }


    @Override
    public SteelPlate getSteelInfo(Roller roller){
        String crane = this.getCraneType();
        SteelPlate steelInfo = null;
        String steelNo2 = "";
        try {
            //获取一级辊道钢板号
            String steelNo = HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,roller.getSteelSignal(),true); //获取钢板号

            if(!"0".equals(steelNo)&& StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7){
                steelNo2= StaticMethod.updateSteelNo(crane,steelNo);
                List<SteelInfo> steels= steelInfoService.selectByMatNo(steelNo2);

                if(steels!=null&&steels.size()==1){
                    log.info("{}天车第一次查询MES数据库中有此钢板号{}",getCraneType(),steelNo2);
                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板号"+steelNo);
                    isSteelInfoChecked=true;
                    steelInfoWrite.setSteelId(steelNo2);
                } else if (steels!=null&&steels.size()>1) {
                    String selectedSteelNo=StaticMethod.autoSelectCurMonthSteelNo(steels,steelNo2,getCraneType());
                    if(selectedSteelNo.equals(steelNo2)){
                        if(!("11C南".equals(crane)||"11C北".equals(crane))){
                            List<SteelInfo> steelsTemp=new ArrayList<>();
                            steelsTemp.add(steels.get(0));
                            steels=steelsTemp;
                            log.info("{}天车第一次查询MES数据库中有多条,默认选择第一条记录",getCraneType());
                            taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条，默认选择第一条记录");
                            isSteelInfoChecked=true;
                            steelInfoWrite.setSteelId(selectedSteelNo);
                        }else {
                            log.info("{}天车第一次查询MES数据库中有多条此钢板号{}信息",getCraneType(),steelNo2);
                            taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条此钢板号"+steelNo2+"信息,更正");
                            isSteelInfoChecked=false;
                        }

                    }else{
                        log.info("{}天车第一次查询MES数据库中有多条,默认选择此钢板号{}",getCraneType(),selectedSteelNo);
                        taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条，默认选此钢板号"+selectedSteelNo);
                        isSteelInfoChecked=true;
                        steelInfoWrite.setSteelId(selectedSteelNo);
                    }

                } else{
                    log.info("{}天车第一次查询MES数据库中无此钢板号{}",getCraneType(),steelNo2);
                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中无此钢板号"+steelNo+"，更正");
                    isSteelInfoChecked=false;
                }


            }

            String steelNo3= steelInfoWrite.getSteelId();

            List<SteelInfo> steelList= steelInfoService.selectByMatNo(steelNo3);

            if(steelList==null||(steelList!=null&&steelList.size()==0)){
                taskStatus.setUnnormalByCraneType(getCraneType(),"无钢板信息，采用录入长宽厚");
                log.error("{}天车MES数据库中无此钢板号{},采用录入长宽厚信息",getCraneType(),steelNo3);
                steelInfo=steelInfoWrite;
            }else if(steelList!=null&&steelList.size()>1){
                if(!("11C南".equals(crane)||"11C北".equals(crane))) {
                    steelInfo=new SteelPlate();
                    steelInfo.setSteelId(steelList.get(0).getMatNo());
                    steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                    steelInfo.setWidth(Math.round(steelList.get(0).getMatActWidth()));
                    steelInfo.setThickness(Math.round(steelList.get(0).getMatActThick()));
                    steelInfo.setWeight(Math.round(steelList.get(0).getMatActWt()));
                    taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有多条,默认选择第一条记录");
                    log.info("{}天车第二次查询MES数据库中有多条,默认选择第一条记录",getCraneType());
                }else {
                    taskStatus.setUnnormalByCraneType(getCraneType(),"有多条钢板信息，采用录入长宽厚");
                    log.error("{}天车MES数据库中有多条此钢板号{}信息,采用录入长宽厚信息",getCraneType(),steelNo3);
                    steelInfo=steelInfoWrite;
                }

            }else if(steelList!=null&&steelList.size()==1){
                taskStatus.setUnnormalByCraneType(getCraneType(),"数据库中有此钢板信息，可采用");
                log.info("{}天车第二次查询MES数据库中有此钢板号{}，可采用",getCraneType(),steelNo3);
                steelInfo=new SteelPlate();
                if("11C南".equals(crane)||"11C北".equals(crane)) {
                    String combStr=StaticMethod.getYearAndMonthJoin();
                    if(StringUtils.isNotEmpty(steelNo)&&steelNo.length()>=7&&(steelNo3.equals(steelNo2)||(steelNo3.length()==11&&steelNo3.startsWith(combStr)))){
                        steelInfo.setSteelId(steelNo);
                        String length= HttpPLCUtils.plcReadbc(restTemplate,serverHost,crane,"dj2dj3钢板长度",true);
                        log.info("{}天车从一级辊道PLC获取钢板长度为{}",crane,length);
                        steelInfo.setLength(Math.round(Float.parseFloat(length)*1000));
                    }else{
                        steelInfo.setSteelId(steelList.get(0).getMatNo());
                        steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                    }
                }else {
                    steelInfo.setSteelId(steelList.get(0).getMatNo());
                    steelInfo.setLength(Math.round(steelList.get(0).getMatActLen()));
                }
                steelInfo.setWidth(Math.round(steelList.get(0).getMatActWidth()));
                steelInfo.setThickness(Math.round(steelList.get(0).getMatActThick()));
                steelInfo.setWeight(Math.round(steelList.get(0).getMatActWt()));
            }


        } catch (Exception e){

        }
        return steelInfo;
    }



    @Override
    public SteelPlate getFrontPageSteelInfo(){

        return this.steelInfoWrite;

    }


    public void setCraneInfoMsg(String msg){
        String craneType = this.getCraneType();
        WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(craneType);
        workStatus.setUnnormalStatus(msg);
    }


    public PublicResult doAction(int step){
        PublicResult result = checkNowStepAndIsHelp(1);
        if (result.isSuccess()) {
            this.semiAutoRunFlag = true;
            this.semiAutoNowStep=1;
            Runnable craneSemiAutoWorkRunnable = () -> {
                boolean resetStepFlag=true;   //恢复semiAutoRunFlag，semiAutoNowStep值
                try {
                    //调试suck多块板用：steelsCount  start
                    int steelsCount=1;
                    //调试suck多块板用：steelsCount  end
                    //生成任务
                    if(plcOperator.upperCraneIsEnter(getCraneType())){
                        taskStatus.setUnnormalByCraneType(getCraneType(),"上层行车闯入，自动任务暂停");
                         throw new Exception("上层行车闯入，自动任务暂停");
                    }
                    if(plcOperator.personIsEnter(getCraneType())){
                        taskStatus.setUnnormalByCraneType(getCraneType(),"门禁有人员闯入，自动任务暂停");
                        throw new Exception("门禁有人员闯入，自动任务暂停");
                    }

                    //修改工作状态
                    String task = "2#横移".equals(this.getCraneType()) ? "online":"offline";
                    WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
                    workStatus.setNowTask("自由半自动");
                    workStatus.setNowMode(task);
                    workStatus.setNowStatus("运行中");
                    workStatus.setUnnormalStatus("");
                    String nowStep = "";
                    switch (step){
                        case 1:
                            nowStep = "move1";
                            break;
                        case 2:
                            nowStep = "suck2";
                            break;
                        case 3:
                            nowStep = "move3";
                            break;
                        case 4:
                            nowStep = "place4";
                            break;
                        default:
                            nowStep = "未知步骤";
                    }
                    workStatus.setNowStep(nowStep);
                    taskStatus.setWorkStatusByCraneType(getCraneType(), workStatus);
                    //与电气PLC交互，执行指令
                    this.execute(step,task);

                } catch (TaskRunningException ee){
                    resetStepFlag=true;
                    taskStatus.setUnnormalByCraneType(getCraneType(),"任务已被停止");
                } catch (Exception e) {
                    resetStepFlag=true;
                    log.error(e.getMessage(),e);
                    e.printStackTrace();
                }
                finally {
                    if(!resetStepFlag){
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=2;
                    }else {
                        log.debug("move1 resetStepFlag生效");
                        this.semiAutoRunFlag = false;
                        this.semiAutoNowStep=0;
                    }
                }
            };

            setNowThread(craneSemiAutoWorkRunnable);
            ThreadPoolOperator.getInstance().submitWorkThread(craneSemiAutoWorkRunnable);
            return PublicResult.ok("启动成功");
        }
        return PublicResult.fail(result.getMsg());

    }

    private void execute(int step, String task) throws Exception {
        if(step == 1 ){
            carSemiAutoService.move1Plus(this.getCraneType(),task);
        } else if(step == 2){
            carSemiAutoService.suck2Plus(this.getCraneType(),this.steelInfoWrite.getSteelId(),task);
        } else if(step == 3){
            carSemiAutoService.move3Plus(this.getCraneType(),task,this.getStockNo());
        } else {
            carSemiAutoService.place4Plus(this.getCraneType(),task);
        }
    }


    public void startEasyPlace(String craneType){
        AysnEasyPlaceThread build = AysnEasyPlaceThread.builder().craneWorkService(this).stockNo(this.stockNo).craneType(craneType).host(serverHost).build();
        ThreadPoolManager.getInstance().execute(build);

    }

    public int getSuckedSteelNum(){
        return this.suckedNum;
    }

    public synchronized void setSuckedSteelNum(){
        this.suckedNum = 0;
        WorkStatus workStatus = taskStatus.getWorkStatusByCraneType(getCraneType());
        workStatus.setSuckedNum("0");
        taskStatus.setWorkStatusByCraneType(getCraneType(),workStatus);
    }

}
